﻿using System;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Text;

namespace BepuUtilities
{
    public static unsafe class Vector512
    {
        public static bool IsHardwareAccelerated { get; set; }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static Vector512<T> AndNot<T>(Vector512<T> left, Vector512<T> right)
        {
            return Create(Vector256.AndNot(left._lower, right._lower), Vector256.AndNot(left._upper, right._upper));
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static Vector512<T> BitwiseOr<T>(Vector512<T> left, Vector512<T> right)
        {
            return left | right;
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static ulong ExtractMostSignificantBits<T>(this Vector512<T> vector)
        {
            ulong num = vector._lower.ExtractMostSignificantBits();
            return num | (ulong)vector._upper.ExtractMostSignificantBits() << Vector256<T>.Count;
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public unsafe static Vector512<T> Load<T>(T* source)
        {
            return LoadUnsafe(ref *source);
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static Vector512<T> LoadUnsafe<T>(ref T source)
        {
            ref byte source2 = ref Unsafe.As<T, byte>(ref Unsafe.AsRef(ref source));
            return Unsafe.ReadUnaligned<Vector512<T>>(ref source2);
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static Vector512<T> Xor<T>(Vector512<T> left, Vector512<T> right)
        {
            return left ^ right;
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static Vector512<T> Equals<T>(Vector512<T> left, Vector512<T> right)
        {
            return Create(Vector256.Equals(left._lower, right._lower), Vector256.Equals(left._upper, right._upper));
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static Vector512<T> Create<T>(Vector256<T> lower, Vector256<T> upper)
        {
            Unsafe.SkipInit(out Vector512<T> result);
            result.SetLowerUnsafe(lower);
            result.SetUpperUnsafe(upper);
            return result;
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        internal unsafe static void SetLowerUnsafe<T>(ref this Vector512<T> vector, Vector256<T> value)
        {
            Unsafe.AsRef(ref vector._lower) = value;
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        internal unsafe static void SetUpperUnsafe<T>(ref this Vector512<T> vector, Vector256<T> value)
        {
            Unsafe.AsRef(ref vector._upper) = value;
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        internal unsafe static ref T GetElementUnsafe<T>(ref this Vector512<T> vector, int index)
        {
            ref T source = ref Unsafe.As<Vector512<T>, T>(ref Unsafe.AsRef(ref vector));
            return ref Unsafe.Add(ref source, index);
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        internal unsafe static void SetElementUnsafe<T>(ref this Vector512<T> vector, int index, T value)
        {
            ref T source = ref Unsafe.As<Vector512<T>, T>(ref Unsafe.AsRef(ref vector));
            Unsafe.Add(ref source, index) = value;
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public unsafe static void Store<T>(this Vector512<T> source, T* destination)
        {
            source.StoreUnsafe(ref *destination);
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static void StoreUnsafe<T>(this Vector512<T> source, ref T destination)
        {
            ref byte destination2 = ref Unsafe.As<T, byte>(ref destination);
            Unsafe.WriteUnaligned(ref destination2, source);
        }
    }

    [DebuggerTypeProxy(typeof(Vector512DebugView<>))]
    [StructLayout(LayoutKind.Sequential, Size = 64)]
    public struct Vector512<T>
    {
        internal Vector256<T> _lower;
        internal Vector256<T> _upper;

        public static Vector512<T> Zero
        {
            get
            {
                return default;
            }
        }
        public static Vector512<T> AllBitsSet
        {
            get
            {
                Vector256<T> allBitsSet = Vector256<T>.AllBitsSet;
                return Vector512.Create(allBitsSet, allBitsSet);
            }
        }
        public static int Count
        {
            [MethodImpl(MethodImplOptions.AggressiveInlining)]
            get
            {
                return Vector256<T>.Count * 2;
            }
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static Vector512<T> operator |(Vector512<T> left, Vector512<T> right)
        {
            return Vector512.Create(left._lower | right._lower, left._upper | right._upper);
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static Vector512<T> operator ^(Vector512<T> left, Vector512<T> right)
        {
            return Vector512.Create(left._lower ^ right._lower, left._upper ^ right._upper);
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public override string ToString()
        {
            return ToString("G", CultureInfo.InvariantCulture);
        }

        private unsafe string ToString([StringSyntax("NumericFormat")] string format, IFormatProvider formatProvider)
        {
            var valueStringBuilder = new StringBuilder();
            string numberGroupSeparator = NumberFormatInfo.GetInstance(formatProvider).NumberGroupSeparator;
            valueStringBuilder.Append('<');
            valueStringBuilder.Append(((IFormattable)(object)this.GetElementUnsafe(0)).ToString(format, formatProvider));
            for (int i = 1; i < Count; i++)
            {
                valueStringBuilder.Append(numberGroupSeparator);
                valueStringBuilder.Append(' ');
                valueStringBuilder.Append(((IFormattable)(object)this.GetElementUnsafe(i)).ToString(format, formatProvider));
            }
            valueStringBuilder.Append('>');
            return valueStringBuilder.ToString();
        }
    }
}
